home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 11
/
CU Amiga Magazine's Super CD-ROM 11 (1997)(EMAP Images)(GB)(Track 1 of 3)[!][issue 1997-06].iso
/
cucd
/
graphics
/
mpimage
/
si
/
parse.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-12-01
|
11KB
|
451 lines
/*
* parse.c - iffparse file IO support module
* based on some of looki.c by Leo Schwab
*
* The filename for clipboard is -c or -cUnit as in -c0 -c1 etc. (default 0)
*
* 39.10 - fix CloseClipboard() cast to (struct ClipboardHandle *)
*/
#include <exec/types.h>
#include "iffp/iff.h"
#define CATCOMP_NUMBERS
#include "messages.h"
/* local function prototypes */
static LONG __asm stdio_stream(register __a0 struct Hook *, register __a2 struct IFFHandle *, register __a1 struct IFFStreamCmd *);
UBYTE *omodes[2] = {"r","w"};
/* openifile
*
* Passed a ParseInfo structure with a not-in-use IFFHandle, filename
* ("-c" or -cUnit like "-c1" for clipboard), and IFF open mode
* (IFFF_READ or IFFF_WRITE) opens file or clipboard for use with
* iffparse.library support modules.
*
* Returns 0 for success or an IFFERR (libraries/iffparse.h)
*/
LONG openifile(struct ParseInfo *pi, UBYTE *filename, ULONG iffopenmode)
{
struct IFFHandle *iff;
BOOL cboard;
ULONG unit = PRIMARY_CLIP;
LONG error;
if(!pi) return(CLIENT_ERROR);
if(!(iff=pi->iff)) return(CLIENT_ERROR);
cboard = (*filename == '-' && filename[1] == 'c');
if(cboard && filename[2]) unit = atoi(&filename[2]);
if (cboard)
{
/*
* Set up IFFHandle for Clipboard I/O.
*/
pi->clipboard = TRUE;
if (!(iff->iff_Stream =
(ULONG)OpenClipboard(unit)))
{
message1(SI(MSG_IFFP_NOCLIP_D),unit);
return(NOFILE);
}
InitIFFasClip(iff);
}
else
{
pi->clipboard = FALSE;
/*
* Set up IFFHandle for buffered stdio I/O.
*/
if (!(iff->iff_Stream = (ULONG)
fopen(filename, omodes[iffopenmode & 1])))
{
message1(SI(MSG_IFFP_NOFILE_S),filename);
return(NOFILE);
}
else initiffasstdio(iff);
}
D(bug("%s file opened: \n", cboard ? "[Clipboard]" : (char *)filename));
pi->filename = filename;
error=OpenIFF(iff, iffopenmode);
pi->opened = error ? FALSE : TRUE; /* currently open handle */
D(bug("OpenIFF error = %ld\n",error));
return(error);
}
/* closeifile
*
* closes file or clipboard opened with openifile, and frees all
* iffparse context parsed by parseifile.
*
* Note - You should closeifile as soon as possible if using clipboard
* ("-c[n]"). You also need to closeifile if, for example, you wish to
* reopen the file to write changes back out. See the copychunks.c
* module for routines which allow you clone the chunks iffparse has
* gathered so that you can closeifile and still be able to modify and
* write back out gathered chunks.
*
*/
void closeifile(struct ParseInfo *pi)
{
struct IFFHandle *iff;
D(bug("closeifile:\n"));
if(!pi) return;
if(!(iff=pi->iff)) return;
DD(bug("closeifile: About to CloseIFF if open, iff=$%lx, opened=%ld\n",
iff, pi->opened));
if(pi->opened) CloseIFF(iff);
DD(bug("closeifile: About to close %s, stream=$%lx\n",
pi->clipboard ? "clipboard" : "file", iff->iff_Stream));
if(iff->iff_Stream)
{
if (pi->clipboard)
CloseClipboard((struct ClipboardHandle *)(iff->iff_Stream));
else
fclose ((FILE *)(iff->iff_Stream));
}
iff->iff_Stream = NULL;
pi->clipboard = NULL;
pi->opened = NULL;
}
/* parseifile
*
* Passed a ParseInfo with an initialized and open IFFHandle,
* grouptype (like ID_FORM), groupid (like ID_ILBM),
* and TAG_DONE terminated longword arrays of type,id
* for chunks to be grabbed, gathered, and stopped on
* (like { ID_ILBM, ID_BMHD, ID_ILBM, ID_CAMG, TAG_DONE })
* will parse an IFF file, grabbing/gathering and stopping
* on specified chunk.
*
* Note - you can call getcontext() (to continue after a stop chunk) or
* nextcontext() (after IFFERR_EOC, to parse next form in the same file)
* if you wish to continue parsing the same IFF file. If parseifile()
* has to delve into a complex format to find your desired FORM, the
* pi->hunt flag will be set. This should be a signal to you that
* you may not have the capability to simply modify and rewrite
* the data you have gathered.
*
* Returns 0 for success else and IFFERR (libraries/iffparse.h)
*/
LONG parseifile(pi,groupid,grouptype,propchks,collectchks,stopchks)
struct ParseInfo *pi;
LONG groupid, grouptype;
LONG *propchks, *collectchks, *stopchks;
{
struct IFFHandle *iff;
register struct ContextNode *cn;
LONG error = 0L;
D(bug("parseifile:\n"));
if(!(iff=pi->iff)) return(CLIENT_ERROR);
if(!iff->iff_Stream) return(IFFERR_READ);
pi->hunt = FALSE;
/*
* Declare property, collection and stop chunks.
*/
if (propchks)
if (error = PropChunks (iff, propchks, chkcnt(propchks)))
return (error);
if (collectchks)
if (error =
CollectionChunks(iff, collectchks, chkcnt(collectchks)))
return (error);
if (stopchks)
if (error = StopChunks (iff, stopchks, chkcnt(stopchks)))
return (error);
/*
* We want to stop at the end of an ILBM context.
*/
if (grouptype)
if (error = StopOnExit (iff, grouptype, groupid))
return(error);
/*
* Take first parse step to enter main chunk.
*/
if (error = ParseIFF (iff, IFFPARSE_STEP))
return(error);
/*
* Test the chunk info to see if simple form of type we want (ILBM).
*/
if (!(cn = CurrentChunk (iff)))
{
/*
* This really should never happen. If it does, it means
* our parser is broken.
*/
message(SI(MSG_IFFP_NOTOP));
return(NOFILE);
}
if (cn->cn_ID != groupid || cn->cn_Type != grouptype)
{
D(bug("This is a(n) %.4s.%.4s. Looking for embedded %.4s's...\n",
&cn->cn_Type, &cn->cn_ID, &grouptype));
pi->hunt = TRUE; /* Warning - this is a complex file */
}
if(!error) error = getcontext(iff);
return(error);
}
/* chkcnt
*
* simply counts the number of chunk pairs (type,id) in array
*/
LONG chkcnt(LONG *taggedarray)
{
LONG k = 0;
while(taggedarray[k] != TAG_DONE) k++;
return(k>>1);
}
/* currentchunkis
*
* returns the ID of the current chunk (like ID_CAMG)
*/
LONG currentchunkis(struct IFFHandle *iff, LONG type, LONG id)
{
register struct ContextNode *cn;
LONG result = 0;
if (cn = CurrentChunk (iff))
{
if((cn->cn_Type == type)&&(cn->cn_ID == id)) result = 1;
}
return(result);
}
/* contextis
*
* returns the enclosing context of the current chunk (like ID_ILBM)
*/
LONG contextis(struct IFFHandle *iff, LONG type, LONG id)
{
register struct ContextNode *cn;
LONG result = 0;
if (cn = (CurrentChunk (iff)))
{
if (cn = (ParentChunk(cn)))
{
if((cn->cn_Type == type)&&(cn->cn_ID == id)) result = 1;
}
}
D(bug("This is a %.4s %.4s\n",&cn->cn_Type,&cn->cn_ID));
return(result);
}
/* getcontext()
*
* Continues to gather the context which was specified to parseifile(),
* stopping at specified stop chunk, or end of context, or EOF
*
* Returns 0 (stopped on a stop chunk)
* or IFFERR_EOC (end of context, not an error)
* or IFFER_EOF (end of file)
*/
LONG getcontext(iff)
struct IFFHandle *iff;
{
LONG error = 0L;
/* Based on our parse initialization,
* ParseIFF() will return on a stop chunk (error = 0)
* or end of context for an ILBM FORM (error = IFFERR_EOC)
* or end of file (error = IFFERR_EOF)
*/
return(error = ParseIFF(iff, IFFPARSE_SCAN));
}
/* nextcontext
*
* If you have finished parsing and reading your context (IFFERR_EOC),
* nextcontext will enter the next context contained in the file
* and parse it.
*
* Returns 0 or an IFFERR such as IFFERR_EOF (end of file)
*/
LONG nextcontext(iff)
struct IFFHandle *iff;
{
LONG error = 0L;
error = ParseIFF(iff, IFFPARSE_STEP);
D(bug("nextcontext: Got through next step\n"));
return(error);
}
/* findpropdata
*
* finds specified chunk parsed from IFF file, and
* returns pointer to its sp_Data (or 0 for not found)
*/
UBYTE *findpropdata(iff, type, id)
struct IFFHandle *iff;
LONG type, id;
{
register struct StoredProperty *sp;
if(sp = FindProp (iff, type, id)) return(sp->sp_Data);
return(0);
}
/*
* File I/O hook functions which the IFF library will call.
* A return of 0 indicates success (no error).
*
* Iffparse.library calls this code via struct Hook and Hook.asm
*/
static LONG
__asm stdio_stream(register __a0 struct Hook *hook,
register __a2 struct IFFHandle *iff,
register __a1 struct IFFStreamCmd *actionpkt) // MJP
{
register FILE *stream;
register LONG nbytes;
register int actual;
register UBYTE *buf;
long len;
stream = (FILE *) iff->iff_Stream;
if(!stream) return(1);
nbytes = actionpkt->sc_NBytes;
buf = (UBYTE *) actionpkt->sc_Buf;
switch (actionpkt->sc_Command) {
case IFFCMD_READ:
do {
actual = nbytes > 32767 ? 32767 : nbytes;
if ((len=fread (buf, 1, actual, stream)) != actual)
break;
nbytes -= actual;
buf += actual;
} while (nbytes > 0);
return (nbytes ? IFFERR_READ : 0 );
case IFFCMD_WRITE:
do {
actual = nbytes > 32767 ? 32767 : nbytes;
if ((len=fwrite (buf, 1, actual, stream)) != actual)
break;
nbytes -= actual;
buf += actual;
} while (nbytes > 0);
return (nbytes ? IFFERR_WRITE : 0);
case IFFCMD_SEEK:
return ((fseek (stream, nbytes, 1) == -1) ? IFFERR_SEEK : 0);
default:
/* No _INIT or _CLEANUP required. */
return (0);
}
}
/* initiffasstdio (ie. init iff as stdio)
*
* sets up hook callback for the file stream handler above
*/
void initiffasstdio (iff)
struct IFFHandle *iff;
{
// extern LONG HookEntry(); MJP
static struct Hook stdiohook = {
{ NULL },
/* (ULONG (*)()) HookEntry, MJP
(ULONG (*)()) stdio_stream,
*/
(ULONG (*)()) stdio_stream,
(ULONG (*)()) NULL,
NULL
};
/*
* Initialize the IFF structure to point to the buffered I/O
* routines. Unbuffered I/O is terribly slow.
*/
InitIFF (iff, IFFF_FSEEK | IFFF_RSEEK, &stdiohook);
}
/*
* PutCk
*
* Writes one chunk of data to an iffhandle
*
*/
long PutCk(struct IFFHandle *iff, long id, long size, void *data)
{
long error = 0, wlen;
D(bug("PutCk: asked to push chunk \"%.4s\" ($%lx) length %ld\n",&id,id,size));
if(error=PushChunk(iff, 0, id, size))
{
D(bug("PutCk: PushChunk of %.4s, error = %s, size = %ld\n",
id, IFFerr(error), id));
}
else
{
D(bug("PutCk: PushChunk of %.4s, error = %ld\n",&id, error));
/* Write the actual data */
if((wlen = WriteChunkBytes(iff,data,size)) != size)
{
D(bug("WriteChunkBytes error: size = %ld, wrote %ld\n",size,wlen));
error = IFFERR_WRITE;
}
else error = PopChunk(iff);
D(bug("PutCk: After PopChunk - error = %ld\n",error));
}
return(error);
}